using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using UCS.XNA.Utils.Animation;

namespace UCS.XNA.Utils
{
    public class MenuItem : IDrawable, IFadeAnimatable
    {
        #region Attributes and Properties

        private string _text;
        public string Text
        {
            get { return this._text; }
            set
            {
                this._text = value;
                this.InitializeTextPosition();
            }
        }

        private Rectangle _bounds;
        public virtual Rectangle Bounds
        {
            get { return this._bounds; }
            set
            {
                this._bounds = value;
                this.InitializeTextPosition();

                if (_border != null)
                    _border.Bounds = _bounds;
                if (_hoveringBorder != null)
                    _hoveringBorder.Bounds = _bounds;
            }
        }

        private SpriteFont _spriteFont;
        public SpriteFont SpriteFont
        {
            get { return this._spriteFont; }
            set { this._spriteFont = value; }
        }

        protected bool _visible;
        public bool Visible
        {
            get { return this._visible; }
        }

        protected bool _enabled;
        public bool Enabled
        {
            get { return this._enabled; }
        }

        private bool _focused;
        public virtual bool Focused
        {
            get { return this._focused; }
            set
            {
                this._focused = value;

                if (this._focused && this.GotFocus != null)
                    this.GotFocus(this, new EventArgs());
            }
        }

        private float _transparency;
        public float Transparency
        {
            get { return this._transparency; }
            set { this._transparency = value; }
        }

        public int DrawOrder
        {
            get { throw new NotImplementedException(); }
        }

        private Border _border;
        public Border Border
        {
            get { return this._border; }
            set
            {
                this._border = value;

                if (this._border != null)
                    this._border.Bounds = this._bounds;
            }
        }

        private Border _hoveringBorder;
        public Border HoveringBorder
        {
            get { return _hoveringBorder; }
            set
            {
                _hoveringBorder = value;

                if (_hoveringBorder != null)
                    _hoveringBorder.Bounds = _bounds;
            }
        }

        private Color _foreColor = Color.LightGray;
        public Color ForeColor
        {
            get { return _foreColor; }
            set { _foreColor = value; }
        }

        private Color _hoveringForeColor = Color.LightGray;
        public Color HoveringForeColor
        {
            get { return _hoveringForeColor; }
            set { _hoveringForeColor = value; }
        }

        private Texture2D _backgroundTexture;
        public Texture2D BackgroundTexture
        {
            get { return _backgroundTexture; }
            set { _backgroundTexture = value; }
        }

        private Texture2D _backgroundHoveringTexture;
        public Texture2D BackgroundHoveringTexture
        {
            get { return _backgroundHoveringTexture; }
            set { _backgroundHoveringTexture = value; }
        }

        #endregion

        #region Private Members

        private bool _isClicked;
        private bool _isMouseHovering;
        private Border _currentBorder;

        #endregion

        #region Protected Members

        protected Vector2 _textPosition;
        protected FadeAnimation _fadeAnimation;

        #endregion

        #region Events

        public event EventHandler<EventArgs> DrawOrderChanged;
        public event EventHandler<EventArgs> VisibleChanged;
        public event EventHandler<EventArgs> EnabledChanged;
        public event EventHandler<EventArgs> UpdateOrderChanged;
        public event EventHandler<EventArgs> Click;
        public event EventHandler<EventArgs> GotFocus;
        public event EventHandler<EventArgs> Hid;
        public event EventHandler<EventArgs> Showed;

        #endregion

        #region Constructors

        public MenuItem(string text, SpriteFont spriteFont)
        {
            this._text = text;
            this._spriteFont = spriteFont;

            this.InitializeBackgroundTexture();
            this.InitializeBackgroundHoveringTexture();
        }

        #endregion

        #region Public Methods

        public virtual void Update(GameTime gameTime, MouseState mouseState, KeyboardState keyboardState)
        {
            if (_enabled)
            {
                _isMouseHovering = _bounds.Contains(mouseState.X, mouseState.Y);

                if (_isMouseHovering)
                {
                    _currentBorder = _hoveringBorder;
                    if (!_isClicked && mouseState.LeftButton == ButtonState.Pressed)
                        _isClicked = true;
                    else if (_isClicked && mouseState.LeftButton == ButtonState.Released)
                    {
                        if (this.Click != null)
                            this.Click(this, new EventArgs());

                        this.Focused = true;
                        _isClicked = false;
                    }
                }
                else
                {
                    _currentBorder = _border;
                    _isClicked = false;
                }
            }

            if (_fadeAnimation != null)
                _fadeAnimation.Update(gameTime);

            if (_currentBorder != null)
                _currentBorder.Update(gameTime);
        }

        public virtual void Draw(GameTime gameTime)
        {
            if (this._visible)
            {
                GameResources.SpriteBatch.Begin();

                this.DrawBackground();
                this.DrawText();

                GameResources.SpriteBatch.End();

                if (_currentBorder != null)
                    _currentBorder.Draw(gameTime);
            }
        }

        public virtual void Hide()
        {
            _enabled = false;
            _fadeAnimation = new FadeOutAnimation(this, 0.05f);
            _fadeAnimation.AnimationFinished += (sender, e) => { _visible = false; this.RaiseHidEvent(); _fadeAnimation = null; };
            _border.Hide();
            _hoveringBorder.Hide();
        }

        public virtual void Show()
        {
            this._visible = true;
            this._enabled = true;

            this._fadeAnimation = new FadeInAnimation(this, 0.05f);
            this._fadeAnimation.AnimationFinished += (sender, e) => { this.RaiseShowedEvent(); this._fadeAnimation = null; };
            if (_border != null)
                _border.Show();
            if (_hoveringBorder != null)
                _hoveringBorder.Show();
        }

        #endregion

        #region Private Methods

        private void InitializeBackgroundTexture()
        {
            Color beginColor = new Color(53, 54, 56);
            Color endColor = new Color(73, 71, 69);

            _backgroundTexture = Texture2DCreator.FromGradient(beginColor, endColor, GameResources.Graphics.GraphicsDevice);
        }

        private void InitializeBackgroundHoveringTexture()
        {
            Color beginColor = new Color(63, 64, 66);
            Color endColor = new Color(83, 81, 79);

            _backgroundHoveringTexture = Texture2DCreator.FromGradient(beginColor, endColor, GameResources.Graphics.GraphicsDevice);
        }

        private void DrawBackground()
        {
            GameResources.SpriteBatch.Draw(_isMouseHovering || _focused ? _backgroundHoveringTexture : _backgroundTexture, _bounds, Color.White * this._transparency);
        }

        private void DrawText()
        {
            GameResources.SpriteBatch.DrawString(_spriteFont, _text, _textPosition, _isMouseHovering || _focused ? _hoveringForeColor : _foreColor * _transparency);
        }

        private void RaiseHidEvent()
        {
            if (this.Hid != null)
                this.Hid(this, new EventArgs());
        }

        private void RaiseShowedEvent()
        {
            if (this.Showed != null)
                this.Showed(this, new EventArgs());
        }

        #endregion

        #region Protected Methods

        protected virtual void InitializeTextPosition()
        {
            var textSize = this._spriteFont.MeasureString(this._text);

            this._textPosition = new Vector2(this._bounds.X + this._bounds.Width / 2 - textSize.X / 2, this._bounds.Y + this._bounds.Height / 2 - textSize.Y / 2);
        }

        #endregion
    }
}
